/*
  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
  Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad

  Stockfish is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Stockfish is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#if !defined(MOVEGEN_H_INCLUDED)
#define MOVEGEN_H_INCLUDED

#include <list>
#include <cassert>
#include "Types.h"
#include "Position.h"
#include "MoveScoreList.h"
using namespace std;
//#include "types.h"

enum MoveType {
  MV_CAPTURE,
  MV_QUIET,
  MV_QUIET_CHECK,
  MV_EVASION,
  MV_NON_EVASION,
  MV_LEGAL
};

class Position;

//template<MoveType> MoveStack* generate(const Position& pos, MoveStack* mlist);

/// The MoveList struct is a simple wrapper around generate(), sometimes comes
/// handy to use this class instead of the low level generate() function.
template<MoveType T>
struct MoveList {

  //explicit MoveList(const Position& pos) : cur(mlist), last(generate<T>(pos, mlist)) {}
  void operator++() { cur++; }
  bool end() const { return cur == last; }
  Move move() const { return cur->move; }
  int size() const { return int(last - mlist); }

private:
  MoveStack mlist[MAX_MOVES];
  MoveStack *cur, *last;
};






inline int GetCol(int square) {return square%8;};
inline int GetRow(int square) {return square/8;};



static bool IsCheckmate(Position& position);
static bool IsCheck(Position& position);
static bool IsCheck(Position& position, bool playerIsWhite);

static void GetLegalMoves(Position& pos, list<Move>& legalMoves);
//static void GetLegalMoves(Position& pos, scorelist& legalMoves);
static void GetPossibleMoves(Position& position, list<Move>& legalMoves);

static void GetPossibleMoves(Position& position, Square square, list<Move>& possibleMoves);
static void GetPossiblePawnMoves(Position& position, bool color, Square square, list<Move>& possibleMoves);
static void GetPossibleKnightMoves(Position& position, bool color, Square square, list<Move>& possibleMoves);
static void GetPossibleBishopMoves(Position& position, bool color, Square square, list<Move>& possibleMoves, int piece = BISHOP);
static void GetPossibleRookMoves(Position& position, bool color, Square square, list<Move>& possibleMoves, int piece = ROOK);
static void GetPossibleQueenMoves(Position& position, bool color, Square square, list<Move>& possibleMoves);
static void GetPossibleKingMoves(Position& position, bool color, Square square, list<Move>& possibleMoves);
static int* GetPiecesLeft(Position& position);

static int Evaluate(Position& position);




// theorical content of .cpp file
//#include "Movegen.h"

static void GetLegalMoves(Position& pos, list<Move>& legalMoves){
    list<Move> pm;
	GetPossibleMoves(pos, pm);
//    list<Move> legalMoves;// = new list<Move>(); 
	for (list<Move>::iterator Move = pm.begin(); Move != pm.end(); Move++)
	{
		Position* newPosition = new Position(pos);
		//StateInfo st;
		newPosition->Play(*Move);//do_Move(*Move, st);
		if(!IsCheck(*newPosition,!newPosition->turn)){
			legalMoves.push_back(*Move);
        }
	}
}

static void GetLegalMoves(Position& pos, list<ScoreMove>& legalMoves){
    list<Move> pm;
	GetPossibleMoves(pos, pm);
//    list<Move> legalMoves;// = new list<Move>(); 
	for (list<Move>::iterator move = pm.begin(); move != pm.end(); move++)
	{
		Position* newPosition = new Position(pos);
		//StateInfo st;
		newPosition->Play(*move);//do_Move(*Move, st);
		if(!IsCheck(*newPosition,!newPosition->turn)){
			ScoreMove sm;
			sm.move = *move;
			sm.score = -VALUE_INFINITE;
			legalMoves.push_back(sm);
        }
	}
}

static void GetPossibleMoves(Position& position, list<Move>& possibleMoves){
	// TODO : implement this method
	//list<Move> Moves;// = new list<Move>();
    for (Square square = SQ_A1; square <= SQ_H8; square++)
        if (position.IsPlayer(square)) 
			GetPossibleMoves(position, square, possibleMoves);
    //return Moves;
}


static void GetPossibleMoves(Position& position, Square square, list<Move>& possibleMoves){
	Piece pieceCode = position.GetPiece(square);
    switch (pieceCode)
    {
        case W_PAWN:
			GetPossiblePawnMoves(position, WHITE, square, possibleMoves);
            break;
        case B_PAWN:
            GetPossiblePawnMoves(position, BLACK, square, possibleMoves);
            break;
		case W_KNIGHT:
            GetPossibleKnightMoves(position, WHITE, square,possibleMoves);
            break;
		case B_KNIGHT:
            GetPossibleKnightMoves(position, BLACK, square,possibleMoves);
            break;
        case W_BISHOP:
			GetPossibleBishopMoves(position, WHITE, square,possibleMoves);
            break;
        case B_BISHOP:
            GetPossibleBishopMoves(position, BLACK, square,possibleMoves);
            break;
        case W_ROOK:
            GetPossibleRookMoves(position, WHITE, square,possibleMoves);
            break;
        case B_ROOK:
            GetPossibleRookMoves(position, BLACK, square,possibleMoves);
            break;
        case W_QUEEN:
            GetPossibleQueenMoves(position, WHITE, square,possibleMoves);
            break;
		case B_QUEEN:
            GetPossibleQueenMoves(position, BLACK, square,possibleMoves);
            break;
        case W_KING:
			GetPossibleKingMoves(position, WHITE, square,possibleMoves);
            break;
		case B_KING:
            GetPossibleKingMoves(position, BLACK, square,possibleMoves);
            break;
        default:
            break;
	}
}


static void GetPossiblePawnMoves(Position& position, bool color, Square square, list<Move>& possibleMoves){
	assert(square>7 && square<56);

	list<Move>* pawnMoves = new list<Move> ;//optim
    int col = GetCol(square);
    int row = GetRow(square);
	Square from = square;
	Square to = SQ_NONE;

	/*
	Move.from = square;
	Move.piece = PAWN;
	Move.color = color;    
	Move.cPiece = NO_PIECE_TYPE; // TODO: add capture piece for bitboards
	Move.cColor = 1-color;
	Move.promotion = '\0';
	*/

	
	if (color == WHITE)
	{
		// Pawn's Move
		if (position.IsEmpty(square+8))
		{
			//Move Move = new Move(square, Square.Get(col, row + 1));
			pawnMoves->push_back(make_move(square,square+(Square)8));
		}
		if (row == 1 && position.IsEmpty(square+8) && position.IsEmpty(square+16)) //optim
		{
			//Move Move = new Move(square, Square.Get(col, row + 2));
			//Move Move;
			//Move.from = square;
			//Move.to =square+16;
			//pawnMoves->push_back(make_move(square,square+(Square)16));
			to = square+(Square)16;
		}
		// Pawn capture
		if (col < 7 && position.IsPieceBlack(position.GetPiece(square+9))) //optim
		{
			//Move Move = new Move(square, Square.Get(col + 1, row + 1));
			//Move Move;
			//Move.from = square;
			//Move.to = square+9;
			//pawnMoves->push_back(make_move(square,square+(Square)9));
			to = square+(Square)9;
		}
		if (col > 0 && position.IsPieceBlack(position.GetPiece(square+7))) //optim
		{
			//Move Move = new Move(square, Square.Get(col - 1, row + 1));
			//Move Move;
			//Move.from = square;
			//Move.to = square+7;
			//pawnMoves->push_back(make_move(square, square+(Square)7));
			to = square+(Square)7;
		}
	} else // color == BLACK
	{
		// Pawn's Move
		if (position.IsEmpty(square-8))//optim
		{
			//Move Move = new Move(square, Square.Get(col, row - 1));
			//Move Move;
			//Move.from = square;
			//Move.to = square-8;
			//pawnMoves->push_back(make_move(square,square-(Square)8));
			to = square-(Square)8;
		}
		if (row == 6 && position.IsEmpty(square-8) && position.IsEmpty(square-16)) //optim
	       
		{
			//Move Move = new Move(square, Square.Get(col, row - 2));
			//Move Move;
			//Move.from = square;
			//Move.to = square-16;
			//pawnMoves->push_back(make_move(square,square-(Square)16));
			to = square-(Square)16;

		}
		// Pawn capture
		if (col < 7 && position.IsPieceWhite(position.GetPiece(square-7)))//optim
		{
			//Move Move = new Move(square, Square.Get(col + 1, row - 1));
			//Move Move;
			//Move.from = square;
			//Move.to = square-7;
			//pawnMoves->push_back(make_move(square,square-(Square)7));
			to = square-(Square)7;
		}
		if (col > 0 && position.IsPieceWhite(position.GetPiece(square-9)))//optim
		{
			//Move Move = new Move(square, Square.Get(col - 1, row - 1));
			//Move Move;
			//Move.from = square;
			//Move.to = square-9;
			//pawnMoves->push_back(make_move(square,square-(Square)9));
			to = square-(Square)9;
		}
	}

	assert(to != SQ_NONE);
	possibleMoves.push_back(make_move(square,to));

	// adding alternate promotions
	// TODO: improve this part
	for (list<Move>::iterator move = pawnMoves->begin(); move != pawnMoves->end(); move++)
	{
		// TODO : migrate this part
		/*
		int r = GetRow(move->to);
		if (r == 0 || r == 7)
		{
			make_promotion(
			//Move->promotion = 'q';
			possibleMoves.push_back(*move);
			move->promotion = 'r';
			possibleMoves.push_back(*move);
			move->promotion = 'b';
			possibleMoves.push_back(*move);
			move->promotion = 'n';
			possibleMoves.push_back(*move);
		} else {
			possibleMoves.push_back(*move);
		}
		*/
	}


	// adding en passant Moves (no possible promotion with en-passant)
	if(position.lastEnPassant != SQ_NONE)
	{
		// TODO : migrate this part
		/*
		//Move.cPiece = PAWN;
		int target = position.lastEnPassant;
		if (position.turn == WHITE)
		{
			Move.to = target + 8;
			if (GetCol(target) > 0)
				if(position.GetPiece(target - 1) == W_PAWN)
			{
				Move.from = target - 1;
				possibleMoves.push_back(Move);
			}
			if (GetCol(target) < 7) 
				if(position.GetPiece(target + 1) == W_PAWN)
			{
				Move.from = target + 1;
				possibleMoves.push_back(Move);
			}
		} else
		{
			Move.to = target - 8;
			if (GetCol(target) > 0)
				if(position.GetPiece(target - 1) == B_PAWN)
			{
				Move.from = target - 1;
				possibleMoves.push_back(Move);
			}
			if (GetCol(target) < 7)
				if(position.GetPiece(target + 1) == B_PAWN)
			{
				Move.from = target + 1;
				possibleMoves.push_back(Move);
			}
		}*/
	}
}

static void GetPossibleKnightMoves(Position& position, bool color, Square square, list<Move>& possibleMoves){
	int col = GetCol(square);
    int row = GetRow(square);
	/*Move Move;
	Move.from = square;
	Move.piece = KNIGHT;
	Move.color = color;    
	Move.cPiece = NO_PIECE_TYPE; // TODO: add capture piece for bitboards
	Move.cColor = 1-color;
	Move.promotion = '\0';
	*/

    if (col > 0 && row < 6 && position.IsEmptyOrOpponent(square+15)) //optim
    {
        //Move Move = new Move(piece,color,square, square+15);
        //Move.to = square+15;
		possibleMoves.push_back(make_move(square,square+(Square)15));
    }
    if (col < 7 && row < 6 && position.IsEmptyOrOpponent(square+17)) //optim
    {
        //Move Move = new Move(piece,color,square, square+17); //optim
        //Move.to = square+17;
		possibleMoves.push_back(make_move(square,square+(Square)17));
    }
    if (col < 6 && row < 7 && position.IsEmptyOrOpponent(square+10)) //optim
    {
        //Move Move = new Move(piece,color,square, square+10); //optim
        //Move.to = square+10;
		possibleMoves.push_back(make_move(square,square+(Square)10));
    }
    if (col < 6 && row > 0 && position.IsEmptyOrOpponent(square-6)) //optim
    {
        //Move Move = new Move(piece,color,square, square-6); //optim
        //Move.to = square-6;
		possibleMoves.push_back(make_move(square,square-(Square)6));
    }
    if (col < 7 && row > 1 && position.IsEmptyOrOpponent(square-15)) //optim
    {
        //Move Move = new Move(piece,color,square, square-15);//optim
        //Move.to = square-15;
		possibleMoves.push_back(make_move(square,square-(Square)15));
    }
    if (col > 0 && row > 1 && position.IsEmptyOrOpponent(square - 17))//optim
    {
        //Move Move = new Move(piece,color,square, square-17); //optim
        //Move.to = square-17;
		possibleMoves.push_back(make_move(square,square-(Square)17));
    }
    if (col > 1 && row > 0  && position.IsEmptyOrOpponent(square-10)) //optim
    {
        //Move Move = new Move(piece,color,square, square-10); //optim
        //Move.to = square-10;
		possibleMoves.push_back(make_move(square,square-(Square)10));
    }
    if (col > 1 && row < 7 && position.IsEmptyOrOpponent(square+6))//optim
    {
        //Move Move = new Move(piece,color,square, square+6);//optim
        //Move.to = square+6;
		possibleMoves.push_back(make_move(square,square+(Square)6));
    }
			
}
static void GetPossibleBishopMoves(Position& position, bool color, Square square, list<Move>& possibleMoves, int piece/* = BISHOP*/){
	int col = GetCol(square);
    int row = GetRow(square);
	/*Move Move;
	Move.from = square;
	Move.piece = piece;
	Move.color = color;    
	Move.cPiece = NO_PIECE_TYPE; // TODO: add capture piece for bitboards
	Move.cColor = 1-color;
	Move.promotion = '\0';
	*/
	int i;
    // Up-right Moves
    for (i = 1; i < 8; i++)
    {
        if ((col + i) < 8 && (row + i) < 8 && position.IsEmptyOrOpponent(square + 9*i))//optim
        {
            //Move Move = new Move(piece,color,square, square + i * 9); //optimization
            //Move.to = square + i * 9;
			possibleMoves.push_back(make_move(square,square+(Square)(i * 9)));
            if (!position.IsEmpty(square + i*9)) break;
        }
        else break;
    }

    // Down-right Moves
    for (i = 1; i < 8; i++)
    {
        if ((col + i) < 8 && (row - i) > -1 && position.IsEmptyOrOpponent(square-7*i)) //optimization
        {
            //Move Move = new Move(piece, color,square, square-7*i); //optimization
            //Move.to = square - 7*i ;
			possibleMoves.push_back(make_move(square,square-(Square)(i * 7)));
            if (!position.IsEmpty(square - 7*i)) break;
        }
        else break;
    }

    // Down-left Moves
    for (i = 1; i < 8; i++)
    {
        if ((col - i) > -1 && (row - i) > -1 && position.IsEmptyOrOpponent(square - 9*i)) //optimization
        {
            //Move Move = new Move(piece,color,square, square - 9*i); //optimization
            //Move.to = square - 9*i;
			possibleMoves.push_back(make_move(square,square-(Square)(i * 9)));
            if (!position.IsEmpty(square - 9*i)) break;
        }
        else break;
    }
    // Up-left Moves
    for (i = 1; i < 8; i++)
    {
        if ((col - i) > -1 && (row + i) < 8 && position.IsEmptyOrOpponent(square+7*i)) //optimization
        {
            //Move Move = new Move(piece,color,square, square+7*i); //optimization
            //Move.to = square+7*i;
			possibleMoves.push_back(make_move(square,square+(Square)(i * 7)));
            if (!position.IsEmpty(square+7*i)) break;
        }
        else break;
    }
}

static void GetPossibleRookMoves(Position& position, bool color, Square square, list<Move>& possibleMoves, int piece/* = ROOK*/){
	int col = GetCol(square);
    int row = GetRow(square);
	/*Move Move;
	Move.from = square;
	Move.piece = piece;
	Move.color = color;    
	Move.cPiece = NO_PIECE_TYPE; // TODO: add capture piece for bitboards
	Move.cColor = 1-color;
	Move.promotion = '\0';
	*/

    // Horizontal Moves right
    for (int i = 1; i < 8; i++)
    {
		//Move.to = square + i;
        if ((col + i) < 8 && position.IsEmptyOrOpponent(square+i)) //optim
        {
            //Move Move = new Move(piece,color,square, square + i);
			possibleMoves.push_back(make_move(square,square + (Square)i));
            if (!position.IsEmpty(square+i)) break;
        }
        else break;
    }

    // Horizontal Moves left
    for (int i = 1; i < 8; i++)
    {
		//Move.to = square - i;
        if ((col - i) > -1 && position.IsEmptyOrOpponent(square-i)) //optim
        {
            //Move Move = new Move(piece,color,square, square - i); //optim
			possibleMoves.push_back(make_move(square, square-(Square)i));
            if (!position.IsEmpty(square-i)) break;
        }
        else break;
    }

    // Vertical Moves up
    for (int i = 1; i < 8; i++)
    {
		//Move.to = square + i*8;
        if ((row + i) < 8 && position.IsEmptyOrOpponent(square + i*8)) //optim
        {
            //Move Move = new Move(piece,color,square, square + i*8); //optim
			possibleMoves.push_back(make_move(square,square+(Square)(i*8)));
            if (!position.IsEmpty(square + i*8)) break;
        }
        else break;
    }
    // Vertical Moves down
    for (int i = 1; i < 8; i++)
    {
		//Move.to = square - i*8;
        if ((row - i) > -1 && position.IsEmptyOrOpponent(square - i*8)) //optim
        {
            //Move Move = new Move(piece,color,square, square - i * 8); //optim
			possibleMoves.push_back(make_move(square,square-(Square)(i*8)));
            if (!position.IsEmpty(square - i*8)) break;
        }
        else break;
    }
			
}

static void GetPossibleQueenMoves(Position& position, bool color, Square square, list<Move>& possibleMoves){
	GetPossibleRookMoves(position, color, square, possibleMoves, QUEEN);
    GetPossibleBishopMoves(position, color, square, possibleMoves, QUEEN);
}

static void GetPossibleKingMoves(Position& position, bool color, Square square, list<Move>& possibleMoves){
	int col = GetCol(square);
    int row = GetRow(square);
	/*
	Move Move;
	Move.from = square;
	Move.piece = KING;
	Move.color = color;    
	Move.cPiece = NO_PIECE_TYPE; // TODO: add capture piece for bitboards
	Move.cColor = 1-color;
	Move.promotion = '\0';
	*/

    if (col < 7 && position.IsEmptyOrOpponent(square+1)) //optim
    {
        //Move Move = new Move(square, square+1); //optim
        //Move.to = square+1;
		possibleMoves.push_back(make_move(square,square+(Square)1));
    }
    if (col < 7 && row < 7 && position.IsEmptyOrOpponent(square+9)) //optim
    {
        //Move Move = new Move(square, square+9); //optim
        //Move.to = square+9;
		possibleMoves.push_back(make_move(square,square+(Square)9));
    }
    if (row < 7 && position.IsEmptyOrOpponent(square+8))//optim
    {
        //Move Move = new Move(square, square+8); //optim
        //Move.to = square+8;
		possibleMoves.push_back(make_move(square,square+(Square)8));
    }
    if (col > 0 && row < 7 && position.IsEmptyOrOpponent(square+7))
    {
        //Move Move = new Move(square, square+7); //optim
        //Move.to = square+7;
		possibleMoves.push_back(make_move(square,square+(Square)7));
    }
    if (col > 0 && position.IsEmptyOrOpponent(square-1)) //optim
    {
        //Move Move = new Move(square, square-1); //optim
        //Move.to = square-1;
		possibleMoves.push_back(make_move(square,square-(Square)1));
    }
    if (col > 0 && row > 0 && position.IsEmptyOrOpponent(square-9)) //optim
    {
        //Move Move = new Move(square, square-9);
        //Move.to = square-9;
		possibleMoves.push_back(make_move(square,square-(Square)9));
    }
    if (row > 0 && position.IsEmptyOrOpponent(square-8)) //optim
    {
        //Move Move = new Move(square, square -8); //optim
        //Move.to = square-8;
		possibleMoves.push_back(make_move(square,square-(Square)8));
    }
    if (col < 7 && row > 0 && position.IsEmptyOrOpponent(square-7)) //optim
    {
        //Move Move = new Move(square, square-7);
        //Move.to = square-7;
		possibleMoves.push_back(make_move(square,square-(Square)7));
    }

    // Casteling Moves
    if (position.turn == WHITE)
    {
		square = SQ_E1;
        if (position.whiteCanCastleQueenSide 
            && position.IsEmpty(SQ_B1)
            && position.IsEmpty(SQ_C1)
            && position.IsEmpty(SQ_D1)
            )
        {
            //Move subMove = new Move(Square.E1, Square.D1);
			//Move.to = SQ_D1;
            //Position* posTest = new Position(position);
			position.Play(make_move(SQ_E1,SQ_D1));// do_Move(Move, st);
            if (!IsCheck(position))
            {
				//Move.to = SQ_C1;
                //possibleMoves.push_back(new Move(Square.E1, Square.C1));
				possibleMoves.push_back(make_move(SQ_E1,SQ_C1));
            }
			position.Unplay(make_move(SQ_E1,SQ_D1));
        }
        if (position.whiteCanCastleKingSide
                && position.IsEmpty(SQ_E1)
                && position.IsEmpty(SQ_F1))
        {
            //Move subMove = new Move(Square.E1, Square.F1);
            //Move.to = SQ_F1;
			//Position* posTest = new Position(position);
            position.Play(make_move(SQ_E1,SQ_F1));// do_Move(Move,st);
            if (!IsCheck(position))
            {
                //possibleMoves.push_back(new Move(Square.E1, Square.G1));
				//Move.to = SQ_G1;
				possibleMoves.push_back(make_move(SQ_E1,SQ_G1));
            }
			position.Unplay(make_move(SQ_E1,SQ_F1));
        }
    } else
    {
		square = SQ_E8;
        if (position.blackCanCastleQueenSide 
            && position.IsEmpty(SQ_B8)
            && position.IsEmpty(SQ_C8)
            && position.IsEmpty(SQ_D8))
        {
            //Move subMove = new Move(Square.E8, Square.D8);
            //Move.to = SQ_D8;
			//Position* posTest = new Position(position);
            position.Play(make_move(SQ_E8,SQ_D8));//do_Move(Move,st);
            if (!IsCheck(position))
            {
                //possibleMoves.push_back(new Move(Square.E8, Square.C8));
				//Move.to = SQ_C8;
				possibleMoves.push_back(make_move(SQ_E8,SQ_C8));
            }
			position.Unplay(make_move(SQ_E8,SQ_D8));
        }
        if (position.blackCanCastleKingSide
                && position.IsEmpty(SQ_E8)
                && position.IsEmpty(SQ_F8))
        {
            //Move subMove = new Move(Square.E8, Square.F8);
            //Move.to = SQ_F8;
			//Position* posTest = new Position(position);
			position.Play(make_move(SQ_E8,SQ_F8));//do_Move(Move,st);
			if (!IsCheck(position))
            {
				//possibleMoves.push_back(new Move(Square.E8, Square.G8));
				//Move.to = SQ_G8;
				possibleMoves.push_back(make_move(SQ_E8,SQ_G8));
            }
			position.Unplay(make_move(SQ_E8,SQ_F8));
        }
    }
}


static bool IsCheckmate(Position& position)
{
	list<Move> legalMoves;
	GetLegalMoves(position,legalMoves);
	return (IsCheck(position) && legalMoves.empty());
}

static bool IsCheck(Position& position){
	return IsCheck(position, position.turn);
}

static bool IsCheck(Position& position, bool playerIsWhite){
	//TODO: modify return block to take chessmen power/given check frequency into account
	Piece king = playerIsWhite?W_KING:B_KING;
	Piece oKing = playerIsWhite?B_KING:W_KING;
	Piece oQueen = playerIsWhite?B_QUEEN:W_QUEEN;
	Piece oRook = playerIsWhite?B_ROOK:W_ROOK;
	Piece oBish = playerIsWhite?B_BISHOP:W_BISHOP;
	Piece oKnig = playerIsWhite?B_KNIGHT:W_KNIGHT;
	Piece oPawn = playerIsWhite?B_PAWN:W_PAWN;
	bool oColor = !playerIsWhite;

	// get king square
	Square sq;
	for( sq=SQ_A1 ; sq<= SQ_H8 ; sq++ ) 
		if(position.GetPiece(sq)==king) break;
	File col = file_of(sq);
	Rank row = rank_of(sq);


	// king threat (virtual)
	if(col>0)
		if(position.GetPiece(sq-1)==oKing) return true;
	if(col>0 && row<7)
		if(position.GetPiece(sq+7)==oKing) return true;
	if(row<7)
		if(position.GetPiece(sq+8)==oKing) return true;
	if(col<7 && row<7)
		if(position.GetPiece(sq+9)==oKing) return true;
	if(col<7)
		if(position.GetPiece(sq+1)==oKing) return true;
	if(col<7 && row>0)
		if(position.GetPiece(sq-7)==oKing) return true;
	if(row>0)
		if(position.GetPiece(sq-8)==oKing) return true;
	if(col>0 && row>0)
		if(position.GetPiece(sq-9)==oKing) return true;

	// Pawn threat
	if(playerIsWhite){
		if(col>0 && row<7)
			if(position.GetPiece(sq+7)==oPawn) return true;
		if(col<7 && row<7)
			if(position.GetPiece(sq+9)==oPawn) return true;
	}else{
		if(col>0 && row>0)
			if(position.GetPiece(sq-9)==oPawn) return true;
		if(col<7 && row>0)
			if(position.GetPiece(sq-7)==oPawn) return true;
	}
	
	// Knight threat
    if (col > 0 && row < 6 && position.IsEmptyOrColor(sq+15,oColor)) //optim
		if(position.GetPiece(sq+15)==oKnig) return true;
    if (col < 7 && row < 6 && position.IsEmptyOrColor(sq+17,oColor)) //optim
		if(position.GetPiece(sq+17)==oKnig) return true;
    if (col < 6 && row < 7 && position.IsEmptyOrColor(sq+10,oColor)) //optim
		if(position.GetPiece(sq+10)==oKnig) return true;
    if (col < 6 && row > 0 && position.IsEmptyOrColor(sq-6,oColor)) //optim
		if(position.GetPiece(sq-6)==oKnig) return true;
    if (col < 7 && row > 1 && position.IsEmptyOrColor(sq-15,oColor)) //optim
		if(position.GetPiece(sq-15)==oKnig) return true;
    if (col > 0 && row > 1 && position.IsEmptyOrColor(sq - 17,oColor))//optim
		if(position.GetPiece(sq-17)==oKnig) return true;
    if (col > 1 && row > 0  && position.IsEmptyOrColor(sq-10,oColor)) //optim
		if(position.GetPiece(sq-10)==oKnig) return true;
    if (col > 1 && row < 7 && position.IsEmptyOrColor(sq+6,oColor))//optim
		if(position.GetPiece(sq+6)==oKnig) return true;


	// bishop&queen threat
	int i;
    // Up-right Moves
    for (i = 1; i < 8; i++)
    {
        if ((col + i) < 8 && (row + i) < 8 && position.IsEmptyOrColor(sq + 9*i,oColor))//optim
        {
			int p = position.GetPiece(sq + 9*i);
            if ((p==oBish) || (p==oQueen)) return true;
        }
        else break;
    }

    // Down-right Moves
    for (i = 1; i < 8; i++)
    {
        if ((col + i) < 8 && (row - i) > -1 && position.IsEmptyOrColor(sq-7*i,oColor)) //optimization
        {
            int p = position.GetPiece(sq-7*i);
            if ((p==oBish) || (p==oQueen)) return true;
        }
        else break;
    }

    // Down-left Moves
    for (i = 1; i < 8; i++)
    {
        if ((col - i) > -1 && (row - i) > -1 && position.IsEmptyOrColor(sq - 9*i,oColor)) //optimization
        {
            int p = position.GetPiece(sq - 9*i);
            if ((p==oBish) || (p==oQueen)) return true;
        }
        else break;
    }
    // Up-left Moves
    for (i = 1; i < 8; i++)
    {
        if ((col - i) > -1 && (row + i) < 8 && position.IsEmptyOrColor(sq+7*i,oColor)) //optimization
        {
            int p = position.GetPiece(sq+7*i);
            if ((p==oBish) || (p==oQueen)) return true;
        }
        else break;
    }

	// rook&queen threat
    // Horizontal Moves right
    for (int i = 1; i < 8; i++)
    {
		if ((col + i) < 8 && position.IsEmptyOrColor(sq + i,oColor)) //optim
        {
			int p = position.GetPiece(sq + i);
            if ((p==oRook) || (p==oQueen)) return true;
        }
        else break;
    }

    // Horizontal Moves left
    for (int i = 1; i < 8; i++)
    {
        if ((col - i) > -1 && position.IsEmptyOrColor(sq - i,oColor)) //optim
        {
 			int p = position.GetPiece(sq - i);
            if ((p==oRook) || (p==oQueen)) return true;
        }
        else break;
    }

    // Vertical Moves up
    for (int i = 1; i < 8; i++)
    {
        if ((row + i) < 8 && position.IsEmptyOrColor(sq + i*8,oColor)) //optim
        {
 			int p = position.GetPiece(sq + i*8);
            if ((p==oRook) || (p==oQueen)) return true;
        }
        else break;
    }
    // Vertical Moves down
    for (int i = 1; i < 8; i++)
    {
        if ((row - i) > -1 && position.IsEmptyOrColor(sq - i*8,oColor)) //optim
        {
 			int p = position.GetPiece(sq - i*8);
            if ((p==oRook) || (p==oQueen)) return true;
        }
        else break;
    }

    return false;
}


static int Evaluate(Position& position)
{
	const int coefficients[12] = { 85, 325, 325, 500, 975, 10000000, -85, -325, -325, -500, -975, -10000000 };

    int evaluation = 0;
    // TODO improve the evaluation method

	if (IsCheckmate(position)) return (position.turn ? -VALUE_MATE : VALUE_MATE);
    //if(IsStalemate(position)) return 0;

    // Basic evaluation : just count the pieces for ech side with coefs
    int* pieces = GetPiecesLeft(position);
    for (int i = 0; i < 12; i++)
    {
        evaluation += (pieces[i] * coefficients[i]);
    }

    return evaluation;
}

static int* GetPiecesLeft(Position& position)
{
    int* nB_PAWNieces = new int[12];
    Piece piece = NO_PIECE;
    for (int i = 0; i < 12; i++)
    {
        nB_PAWNieces[i] = 0;
    }
    for (int i = 0; i < 64; i++)
    {
        piece = position.board[i];
		if (piece != NO_PIECE)
        {
            nB_PAWNieces[(int)piece]++;
        }
    }

    return nB_PAWNieces;
}





#endif